/**
 * 
 */
package Dungeon;

import java.util.Iterator;
import java.util.NoSuchElementException;

import squarePackage.SquareImp;
import be.kuleuven.cs.som.annotate.Basic;
import Exceptions.IllegalDimensionException;

/**
 * A class of Levels
 * 
 * @invar 	All the elements in the level have to be valid elements and must have valid coordinates
 * 			|...
 *  			
 * 
 * @author Pieter
 *
 */
public class Level<E extends SquareImp> extends Dungeon<E> implements Iterable<E> {
	
	/**
	 * A constructor to initialize the level dungeon
	 * 
	 * @param 	xMax
	 * 			the maximum x dimension
	 * @param 	yMax
	 * 			the maximum y dimension
	 * @param 	zMax
	 * 			the maximum z dimension
	 * @param	fixedZ
	 * 			the fixed z coordinate for this dungeon
	 * @effect	...
	 * 			|super(xMax, yMax, zMax)
	 * @effect	...
	 * 			|setFixedZ(fixedZ)
	 */
	public Level(long xMax, long yMax, long zMax, long fixedZ) throws IllegalDimensionException {
		super(xMax, yMax, zMax);
		setFixedZ(fixedZ);
	}
	
	/**
	 * Returns the fixed z dimension value for this dungeon
	 */
	@Basic 
	public long getFixedZ() {
		return this.fixedZ;
	}
	
	/**
	 * A variable to store the fixed z value
	 */
	private long fixedZ;
	
	/**
	 *  A method to initialize the fixed Z to a certain value
	 *
	 * @param  	fixedZ
	 * 			the desired fixedZ value for this dungeon
	 * @post	the fixedZ value will be set to this value
	 * 			|...
	 * @throws 	IllegalDimensionException 
	 *			If the desired fixedZ value is not a valid dimension 
	 *			|...
	 */
	private void setFixedZ(long fixedZ) throws IllegalDimensionException{
		if(!isValidDimension(fixedZ, getZ()))
			throw new IllegalDimensionException();
		this.fixedZ = fixedZ;
	}
	
	/**
	 * A method to indicate whether this is a valid coordinate to add
	 * 
	 * @return	...
	 * 			|result == (super.isValidCoordinate(x,y,z) && z != this.getFixedZ())
	 */
	@Override
	public boolean isValidCoordinate(long x, long y, long z){
		return (super.isValidCoordinate(x, y, z) && z == this.getFixedZ());
	}
	
	/**
	 * A method to see whether a dungeon can be a root of another dungeon
	 * 
	 * @param 	dungeon
	 * 			the dungeon you want to check whether it can be a root
	 * @return	...
	 * 			|result == (dungeon == this && !dungeon.isTerminated())
	 */
	@Override
	public  boolean canBeRoot(Dungeon<E> dungeon){
		return (dungeon == this && !dungeon.isTerminated());
	}
	
	/**
	 * Returns an iterator that returns all the squares in the Level
	 */
	@Override
	public Iterator<E> iterator() {
			return new Iterator<E>() {

				/**
				 * An iterator over the squares
				 */
				private Iterator<E> levelIterator = getCoordinatesAndSquaresInDungeon().values().iterator();
				
				/**
				 * Returns true if the iteration has more elements
				 * 
				 * @return	true if the iterator has more elements.
				 * 			|result == levelIterator.hasNext())
				 */
				@Override
				public boolean hasNext() {
					return levelIterator.hasNext();
				}

				/**
				 * Returns the next element in the iteration. 
				 * 
				 * @return	the next element in the iteration. 
				 * 			|result == levelIterator.next()
				 * @throws	NoSuchElementException()
				 * 			...
				 * 			|if(!hasNext())
				 */
				@Override
				public E next() throws NoSuchElementException {
					if(!hasNext()){
						throw new NoSuchElementException();
					}
					else{
						return levelIterator.next();
					}
				}
				
				/**
				 * Removes the last element returned by the iterator
				 * 
				 * @throws 	UnsupportedOperationException
				 *
				 */
				@Override
				public void remove() throws UnsupportedOperationException {
					throw new UnsupportedOperationException();
				}
			};
	}
	
	
	
	
	
	
	
	

}
